package mm.card.util;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * AES加解密工具
 * 
 * @version 1.0
 */
public class AesUtil {
	
	private static final byte[] SEED = new byte[] { 121, 115, 70, 72, 117, 90,
	        120, 103, 92, 107, 34, 57, 75, 104, 61, 91, 38, 96, 60, 34, 34,
	        122, 39, 44, 110, 102, 72, 51, 42, 46, 94, 76, 108, 108, 73, 44,
	        117, 121, 77, 57, 88, 84, 113, 121, 116, 122, 84, 38, 79, 76, 32,
	        42, 44, 76, 88, 68, 84, 88, 113, 97, 89, 69, 83, 51, 80, 50, 65,
	        107, 65, 112, 111, 37, 120, 61, 98, 114, 81, 98, 119, 110, 65, 104,
	        46, 72, 119, 103, 104, 113, 48, 83, 126, 34, 122, 82, 116, 48, 40,
	        111, 103, 122, 84, 88, 102, 115, 81, 99, 87, 63, 74, 48, 116, 95,
	        43, 86, 109, 52, 84, 76, 125, 82, 44, 106, 54, 49, 40, 85, 55, 94,
	        39, 46, 97, 98, 85, 54, 99, 73, 99, 40, 35, 82, 126, 68, 86, 33,
	        121, 70, 62, 82, 63, 108, 33, 77, 55, 106, 49, 77, 68, 72, 90, 64,
	        60, 80, 34, 62, 103, 45, 37, 103, 44, 64, 99, 94, 37, 61, 63, 49,
	        114, 45, 33, 116, 117, 122, 123, 86, 52, 67, 76, 47, 59, 84, 99,
	        125, 109, 80, 46, 35, 83, 112, 114, 85, 68, 61, 126, 33, 114, 121,
	        58, 89, 100, 99, 83, 96, 85, 63, 65, 94, 74, 122, 101, 114, 98,
	        104, 85, 65, 38, 76, 95, 50, 79, 64, 92, 82, 32, 47, 32, 32, 71,
	        55, 102, 113, 47, 101, 64, 125, 93, 116, 79, 116, 61, 106, 62, 100,
	        45, 35, 68, 102, 90, 120, 33, 118, 111, 41, 114, 59, 75, 71, 83,
	        44, 116, 40, 119, 47, 115, 43, 74, 44, 98, 67, 92, 33, 40, 75, 39,
	        118, 54, 115, 84, 64, 51, 115, 64, 96, 126, 42, 90, 84, 72, 125,
	        68, 124, 41, 100, 53, 74, 50, 86, 80, 111, 54, 105, 78, 113, 98,
	        121, 117, 73, 71, 51, 34, 39, 110, 71, 57, 113, 119, 65, 84, 33,
	        118, 101, 93, 126, 123, 80, 105, 103, 118, 39, 68, 103, 35, 63,
	        101, 51, 64, 76, 56, 57, 121, 112, 96, 123, 92, 52, 100, 118, 61,
	        40, 72, 47, 37, 59, 72, 99, 90, 54, 114, 76, 53, 42, 82, 113, 123,
	        45, 102, 73, 65, 90, 100, 45, 98, 105, 49, 48, 124, 114, 104, 82,
	        73, 53, 102, 41, 61, 32, 60, 49, 101, 78, 73, 111, 68, 61, 50, 56,
	        86, 45, 48, 102, 66, 50, 59, 62, 115, 116, 124, 123, 69, 78, 97,
	        107, 46, 108, 123, 35, 89, 83, 79, 48, 114, 101, 62, 45, 110, 60,
	        89, 89, 118, 93, 120, 35, 112, 99, 90, 126, 48, 74, 64, 87, 106,
	        72, 110, 93, 57, 113, 114, 126, 108, 78, 105, 87, 71, 77, 113, 59,
	        74, 48, 85, 52, 62, 65, 40, 81, 65, 42, 74, 58, 91, 41, 37, 76, 65,
	        66, 91, 101, 47, 86, 76, 45, 35, 65, 107, 83, 115, 36, 32, 44, 78,
	        80, 48, 96, 66, 123, 33, 115, 87, 71, 68, 33, 76, 80, 109, 94 };

	    private static final String HEX = "0123456789ABCDEF";

	    private static final int LEVEL = 128;
	    
	    /**
	     * 字符串子集的结束下标
	     */
	    private static final int SUBSTRING_ENDINDEX = 16;
	    
	    /**
	     * 右移4位
	     */
	    private static final int FOUR_MOVES_RIGHT = 4;
	    
	    /**
	     * 代表15的16进制写法
	     */
	    private static final int HEXADECIMAL_FOR_FIFTEEN = 0x0f;
	    

	    /**
	     * 加密信息
	     * 
	     * @param msg 被加密信息
	     * @return 返回加密后的信息
	     * @throws Exception
	     */
	    public static String encrypt(String msg) throws Exception {
	        byte[] rawKey = getRawKey(SEED);
	        byte[] result = encrypt(rawKey, msg.getBytes("UTF-8"));
	        return toHex(result);
	    }

	    /**
	     * 解密信息
	     * 
	     * @param encrypted 加密信息
	     * @return 解密后的信息
	     * @throws Exception
	     */
	    public static String decrypt(String encrypted) throws Exception {
	        byte[] rawKey = getRawKey(SEED);
	        byte[] enc = toByte(encrypted);
	        byte[] result = decrypt(rawKey, enc);
	        return new String(result);
	    }

	    private static byte[] getRawKey(byte[] seed) throws NoSuchAlgorithmException {
	        KeyGenerator kgen = KeyGenerator.getInstance("AES");
	        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
	        sr.setSeed(seed);
	        kgen.init(LEVEL, sr); // 192 and 256 bits may not be available
	        SecretKey skey = kgen.generateKey();
	        byte[] raw = skey.getEncoded();
	        return raw;
	    }

	    private static byte[] encrypt(byte[] raw, byte[] clear) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
	            IllegalBlockSizeException, BadPaddingException {
	        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
	        Cipher cipher = Cipher.getInstance("AES");
	        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
	        byte[] encrypted = cipher.doFinal(clear);
	        return encrypted;
	    }

	    private static byte[] decrypt(byte[] raw, byte[] encrypted) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
	            IllegalBlockSizeException, BadPaddingException {
	        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
	        Cipher cipher = Cipher.getInstance("AES");
	        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
	        byte[] decrypted = cipher.doFinal(encrypted);
	        return decrypted;
	    }

	    private static byte[] toByte(String hexString) {
	        int len = hexString.length() / 2;
	        byte[] result = new byte[len];
	        for (int i = 0; i < len; i++) {
	            result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), SUBSTRING_ENDINDEX).byteValue();
	        }
	        return result;
	    }

	    private static String toHex(byte[] buf) {
	        if (buf == null) {
	            return "";
	        }
	        StringBuffer result = new StringBuffer(2 * buf.length);
	        for (int i = 0; i < buf.length; i++) {
	            appendHex(result, buf[i]);
	        }
	        return result.toString();
	    }

	    private static void appendHex(StringBuffer sb, byte b) {
	        sb.append(HEX.charAt((b >> FOUR_MOVES_RIGHT) & HEXADECIMAL_FOR_FIFTEEN)).append(HEX.charAt(b & HEXADECIMAL_FOR_FIFTEEN));
	    }

	    /**
	     * 加密byte[]信息
	     * 
	     * @param byteInput 被加密信息
	     * @return 返回加密后的信息
	     * @throws Exception
	     */
	    public static byte[] encryptByteArray(byte[] byteInput) throws Exception {
	        byte[] rawKey = getRawKey(SEED);
	        
	        return encrypt(rawKey, byteInput);
	    }

	    /**
	     * 解密byte[]信息
	     * 
	     * @param byteInput 加密信息
	     * @return 解密后的信息
	     * @throws Exception
	     */
	    public static byte[] decryptByteArray(byte[] byteInput) throws Exception {
	        byte[] rawKey = getRawKey(SEED);

	        return decrypt(rawKey, byteInput);
	    }
}
